/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package it.polimi.games.epkb.controller;

import it.polimi.games.epkb.controller.exceptions.IllegalOrphanException;
import it.polimi.games.epkb.controller.exceptions.NonexistentEntityException;
import it.polimi.games.epkb.controller.exceptions.PreexistingEntityException;
import it.polimi.games.epkb.entityClasses.Rack;
import java.io.Serializable;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import it.polimi.games.epkb.entityClasses.Component;
import it.polimi.games.epkb.entityClasses.Isle;
import it.polimi.games.epkb.entityClasses.Server;
import java.util.ArrayList;
import java.util.Collection;
import it.polimi.games.epkb.entityClasses.Storage;
import javax.transaction.UserTransaction;

/**
 *
 * @author plebani
 */
public class RackJpaController implements Serializable {

    public RackJpaController(EntityManagerFactory emf) {
        this.utx = null;
        this.emf = emf;
    }

    public RackJpaController(UserTransaction utx, EntityManagerFactory emf) {
        this.utx = utx;
        this.emf = emf;
    }
    private UserTransaction utx = null;
    private EntityManagerFactory emf = null;

    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }

    public void create(Rack rack) throws IllegalOrphanException, PreexistingEntityException, Exception {
        if (rack.getServerCollection() == null) {
            rack.setServerCollection(new ArrayList<Server>());
        }
        if (rack.getStorageCollection() == null) {
            rack.setStorageCollection(new ArrayList<Storage>());
        }
        List<String> illegalOrphanMessages = null;
        Component componentOrphanCheck = rack.getComponent();
        if (componentOrphanCheck != null) {
            Rack oldRackOfComponent = componentOrphanCheck.getRack();
            if (oldRackOfComponent != null) {
                if (illegalOrphanMessages == null) {
                    illegalOrphanMessages = new ArrayList<String>();
                }
                illegalOrphanMessages.add("The Component " + componentOrphanCheck + " already has an item of type Rack whose component column cannot be null. Please make another selection for the component field.");
            }
        }
        if (illegalOrphanMessages != null) {
            throw new IllegalOrphanException(illegalOrphanMessages);
        }
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Component component = rack.getComponent();
            if (component != null) {
                component = em.getReference(component.getClass(), component.getId());
                rack.setComponent(component);
            }
            Isle IDIsle = rack.getIDIsle();
            if (IDIsle != null) {
                IDIsle = em.getReference(IDIsle.getClass(), IDIsle.getId());
                rack.setIDIsle(IDIsle);
            }
            Collection<Server> attachedServerCollection = new ArrayList<Server>();
            for (Server serverCollectionServerToAttach : rack.getServerCollection()) {
                serverCollectionServerToAttach = em.getReference(serverCollectionServerToAttach.getClass(), serverCollectionServerToAttach.getId());
                attachedServerCollection.add(serverCollectionServerToAttach);
            }
            rack.setServerCollection(attachedServerCollection);
            Collection<Storage> attachedStorageCollection = new ArrayList<Storage>();
            for (Storage storageCollectionStorageToAttach : rack.getStorageCollection()) {
                storageCollectionStorageToAttach = em.getReference(storageCollectionStorageToAttach.getClass(), storageCollectionStorageToAttach.getId());
                attachedStorageCollection.add(storageCollectionStorageToAttach);
            }
            rack.setStorageCollection(attachedStorageCollection);
            em.persist(rack);
            if (component != null) {
                component.setRack(rack);
                component = em.merge(component);
            }
            if (IDIsle != null) {
                IDIsle.getRackCollection().add(rack);
                IDIsle = em.merge(IDIsle);
            }
            for (Server serverCollectionServer : rack.getServerCollection()) {
                Rack oldIdRackOfServerCollectionServer = serverCollectionServer.getIdRack();
                serverCollectionServer.setIdRack(rack);
                serverCollectionServer = em.merge(serverCollectionServer);
                if (oldIdRackOfServerCollectionServer != null) {
                    oldIdRackOfServerCollectionServer.getServerCollection().remove(serverCollectionServer);
                    oldIdRackOfServerCollectionServer = em.merge(oldIdRackOfServerCollectionServer);
                }
            }
            for (Storage storageCollectionStorage : rack.getStorageCollection()) {
                Rack oldIDRackOfStorageCollectionStorage = storageCollectionStorage.getIDRack();
                storageCollectionStorage.setIDRack(rack);
                storageCollectionStorage = em.merge(storageCollectionStorage);
                if (oldIDRackOfStorageCollectionStorage != null) {
                    oldIDRackOfStorageCollectionStorage.getStorageCollection().remove(storageCollectionStorage);
                    oldIDRackOfStorageCollectionStorage = em.merge(oldIDRackOfStorageCollectionStorage);
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            if (findRack(rack.getId()) != null) {
                throw new PreexistingEntityException("Rack " + rack + " already exists.", ex);
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void edit(Rack rack) throws IllegalOrphanException, NonexistentEntityException, Exception {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Rack persistentRack = em.find(Rack.class, rack.getId());
            Component componentOld = persistentRack.getComponent();
            Component componentNew = rack.getComponent();
            Isle IDIsleOld = persistentRack.getIDIsle();
            Isle IDIsleNew = rack.getIDIsle();
            Collection<Server> serverCollectionOld = persistentRack.getServerCollection();
            Collection<Server> serverCollectionNew = rack.getServerCollection();
            Collection<Storage> storageCollectionOld = persistentRack.getStorageCollection();
            Collection<Storage> storageCollectionNew = rack.getStorageCollection();
            List<String> illegalOrphanMessages = null;
            if (componentNew != null && !componentNew.equals(componentOld)) {
                Rack oldRackOfComponent = componentNew.getRack();
                if (oldRackOfComponent != null) {
                    if (illegalOrphanMessages == null) {
                        illegalOrphanMessages = new ArrayList<String>();
                    }
                    illegalOrphanMessages.add("The Component " + componentNew + " already has an item of type Rack whose component column cannot be null. Please make another selection for the component field.");
                }
            }
            if (illegalOrphanMessages != null) {
                throw new IllegalOrphanException(illegalOrphanMessages);
            }
            if (componentNew != null) {
                componentNew = em.getReference(componentNew.getClass(), componentNew.getId());
                rack.setComponent(componentNew);
            }
            if (IDIsleNew != null) {
                IDIsleNew = em.getReference(IDIsleNew.getClass(), IDIsleNew.getId());
                rack.setIDIsle(IDIsleNew);
            }
            Collection<Server> attachedServerCollectionNew = new ArrayList<Server>();
            for (Server serverCollectionNewServerToAttach : serverCollectionNew) {
                serverCollectionNewServerToAttach = em.getReference(serverCollectionNewServerToAttach.getClass(), serverCollectionNewServerToAttach.getId());
                attachedServerCollectionNew.add(serverCollectionNewServerToAttach);
            }
            serverCollectionNew = attachedServerCollectionNew;
            rack.setServerCollection(serverCollectionNew);
            Collection<Storage> attachedStorageCollectionNew = new ArrayList<Storage>();
            for (Storage storageCollectionNewStorageToAttach : storageCollectionNew) {
                storageCollectionNewStorageToAttach = em.getReference(storageCollectionNewStorageToAttach.getClass(), storageCollectionNewStorageToAttach.getId());
                attachedStorageCollectionNew.add(storageCollectionNewStorageToAttach);
            }
            storageCollectionNew = attachedStorageCollectionNew;
            rack.setStorageCollection(storageCollectionNew);
            rack = em.merge(rack);
            if (componentOld != null && !componentOld.equals(componentNew)) {
                componentOld.setRack(null);
                componentOld = em.merge(componentOld);
            }
            if (componentNew != null && !componentNew.equals(componentOld)) {
                componentNew.setRack(rack);
                componentNew = em.merge(componentNew);
            }
            if (IDIsleOld != null && !IDIsleOld.equals(IDIsleNew)) {
                IDIsleOld.getRackCollection().remove(rack);
                IDIsleOld = em.merge(IDIsleOld);
            }
            if (IDIsleNew != null && !IDIsleNew.equals(IDIsleOld)) {
                IDIsleNew.getRackCollection().add(rack);
                IDIsleNew = em.merge(IDIsleNew);
            }
            for (Server serverCollectionOldServer : serverCollectionOld) {
                if (!serverCollectionNew.contains(serverCollectionOldServer)) {
                    serverCollectionOldServer.setIdRack(null);
                    serverCollectionOldServer = em.merge(serverCollectionOldServer);
                }
            }
            for (Server serverCollectionNewServer : serverCollectionNew) {
                if (!serverCollectionOld.contains(serverCollectionNewServer)) {
                    Rack oldIdRackOfServerCollectionNewServer = serverCollectionNewServer.getIdRack();
                    serverCollectionNewServer.setIdRack(rack);
                    serverCollectionNewServer = em.merge(serverCollectionNewServer);
                    if (oldIdRackOfServerCollectionNewServer != null && !oldIdRackOfServerCollectionNewServer.equals(rack)) {
                        oldIdRackOfServerCollectionNewServer.getServerCollection().remove(serverCollectionNewServer);
                        oldIdRackOfServerCollectionNewServer = em.merge(oldIdRackOfServerCollectionNewServer);
                    }
                }
            }
            for (Storage storageCollectionOldStorage : storageCollectionOld) {
                if (!storageCollectionNew.contains(storageCollectionOldStorage)) {
                    storageCollectionOldStorage.setIDRack(null);
                    storageCollectionOldStorage = em.merge(storageCollectionOldStorage);
                }
            }
            for (Storage storageCollectionNewStorage : storageCollectionNew) {
                if (!storageCollectionOld.contains(storageCollectionNewStorage)) {
                    Rack oldIDRackOfStorageCollectionNewStorage = storageCollectionNewStorage.getIDRack();
                    storageCollectionNewStorage.setIDRack(rack);
                    storageCollectionNewStorage = em.merge(storageCollectionNewStorage);
                    if (oldIDRackOfStorageCollectionNewStorage != null && !oldIDRackOfStorageCollectionNewStorage.equals(rack)) {
                        oldIDRackOfStorageCollectionNewStorage.getStorageCollection().remove(storageCollectionNewStorage);
                        oldIDRackOfStorageCollectionNewStorage = em.merge(oldIDRackOfStorageCollectionNewStorage);
                    }
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                String id = rack.getId();
                if (findRack(id) == null) {
                    throw new NonexistentEntityException("The rack with id " + id + " no longer exists.");
                }
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void destroy(String id) throws NonexistentEntityException {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Rack rack;
            try {
                rack = em.getReference(Rack.class, id);
                rack.getId();
            } catch (EntityNotFoundException enfe) {
                throw new NonexistentEntityException("The rack with id " + id + " no longer exists.", enfe);
            }
            Component component = rack.getComponent();
            if (component != null) {
                component.setRack(null);
                component = em.merge(component);
            }
            Isle IDIsle = rack.getIDIsle();
            if (IDIsle != null) {
                IDIsle.getRackCollection().remove(rack);
                IDIsle = em.merge(IDIsle);
            }
            Collection<Server> serverCollection = rack.getServerCollection();
            for (Server serverCollectionServer : serverCollection) {
                serverCollectionServer.setIdRack(null);
                serverCollectionServer = em.merge(serverCollectionServer);
            }
            Collection<Storage> storageCollection = rack.getStorageCollection();
            for (Storage storageCollectionStorage : storageCollection) {
                storageCollectionStorage.setIDRack(null);
                storageCollectionStorage = em.merge(storageCollectionStorage);
            }
            em.remove(rack);
            em.getTransaction().commit();
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public List<Rack> findRackEntities() {
        return findRackEntities(true, -1, -1);
    }

    public List<Rack> findRackEntities(int maxResults, int firstResult) {
        return findRackEntities(false, maxResults, firstResult);
    }

    private List<Rack> findRackEntities(boolean all, int maxResults, int firstResult) {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            cq.select(cq.from(Rack.class));
            Query q = em.createQuery(cq);
            if (!all) {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            return q.getResultList();
        } finally {
            em.close();
        }
    }

    public Rack findRack(String id) {
        EntityManager em = getEntityManager();
        try {
            return em.find(Rack.class, id);
        } finally {
            em.close();
        }
    }

    public int getRackCount() {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            Root<Rack> rt = cq.from(Rack.class);
            cq.select(em.getCriteriaBuilder().count(rt));
            Query q = em.createQuery(cq);
            return ((Long) q.getSingleResult()).intValue();
        } finally {
            em.close();
        }
    }
    
}
